const fp = require('lodash/fp');
const { MayBe, Container } = require('./support');
const MyPromise = require('./myPromise');
const { reject } = require('lodash');

console.log(`
  简答题
  一、谈谈你是如何理解JS异步编程的，EventLoop、消息队列都是做什么的，什么是宏任务，什么是微任务？

  答：
  基于js单线程的设计，为了解决耗时阻塞的问题，js将任务执行模式分为两种：同步模式和异步模式，进而引出异步，
  异步不会等待这个任务的结束才开始下一个任务，开启过后就立即往后执下一个任务
  EventLoop 负责监听调用栈和消息队列 一旦调用栈所有任务都结束后 事件循环就会到消息队列中取出第一个回调函数压入到调用栈
  消息队列 js线程遇到异步，会交给单独的线程维护异步任务，等待某个时机，然后由事件触发线程将异步任务对应的回调函数加入到消息队列中，消息队列中的函数等待被执行
  宏任务 宏任务总会在下一个EventLoop中执行 若在执行宏任务的过程中，加入了新的微任务，会把新的微任务添加到微任务的队列中
  微任务 优先级高，并且可以插队，不是先定义先执行 Promise、MutaionObserver、process.nextTick
  因为微任务的优先级较高，所以会先将微任务的异步任务取出来进行执行，当微任务的任务都执行完毕之后，会将宏任务中的任务取出来执行
`)

 /**
  * 代码题
  * 一、
  */

  const sleep = (times, data) => { 
    return new Promise((reslove) => { 
      setTimeout(()=>reslove(data), times)
    })
  }


  sleep(10).then(() => { 
    const a = 'hello'
    return sleep(10, {a})
  }).then(({a}) => { 
    const b = 'lagou'
    return sleep(10, {a, b})
  }).then(({a, b}) => {
    const c = 'I ❤ U'
    console.log(a + b + c)
  })


  /**
  * 代码题
  * 二、
  */

const cars = [
  {
    name: 'Ferrari FF',
    horsepower: 660,
    dollar_value: 700000,
    in_stock: true
  },
  {
    name: 'Spyker C12 Zagato',
    horsepower: 650,
    dollar_value: 648000,
    in_stock: false
  },
  {
    name: 'Jaguar XKR-S',
    horsepower: 550,
    dollar_value: 132000,
    in_stock: false
  },
  {
    name: 'Audi R8',
    horsepower: 525,
    dollar_value: 114200,
    in_stock: false
  },
  {
    name: 'Aston Martin One—77',
    horsepower: 750,
    dollar_value: 1850000,
    in_stock: true
  },
  {
    name: 'Pagani Huayra',
    horsepower: 700,
    dollar_value: 1300000,
    in_stock: false
  },
]

const isLastInStock = fp.flowRight(fp.prop('in_stock'), fp.last)
console.log('二、1. :', isLastInStock(cars))

const getFirstName = fp.flowRight(fp.prop('name'), fp.first)
console.log('二、2. :', getFirstName(cars))

const _average = function (xs) { 
  return fp.reduce(fp.add, 0, xs) / xs.length
}

// const averageDollarValue = function (cars) { 
//   const dollar_values = fp.map(function (car) { 
//     return car.dollar_value
//   }, cars)

//   return _average(dollar_values)
// }


const averageDollarValue = fp.flowRight(_average, fp.map((car) => car.dollar_value))

console.log('二、3. :', averageDollarValue(cars))

const _underscore = fp.replace(/\W+/g, '_')

const sanitizeNames = fp.flowRight(fp.map(fp.flowRight(_underscore, fp.toLower, (car) => car.name)))
console.log('二、4. :', sanitizeNames(cars))



const maybe = MayBe.of([5, 6, 1]);
const ex1 = (n, m) => { 
  return n.map(fp.map(fp.add(m)))._value
}
console.log('三、1. :', ex1(maybe, 4))

const xs = Container.of(['do', 'ray', 'me', 'fa', 'so', 'la', 'ti', 'do'])

const ex2 = (n) => {
  return n.map(fp.first)._value
}

console.log('三、2. :', ex2(xs))


const safeProp = fp.curry(function (x, o) { 
  return MayBe.of(o[x])
})
const user = {
  id: 2,
  name: 'Albert'
}

const ex3 = (x, o) => {
  return safeProp(x, o).map(fp.first)._value
}

console.log('三、3. :', ex3('name', user))

const ex4 = (n) => {
  return MayBe.of(n).map(parseInt)._value
}

console.log('三、4. :', ex4(6.4))

const promise = new MyPromise((reslove, reject) => { 
  setTimeout(() => { 
    reslove('你好')
  }, 4000)

  // throw '错误'
}).then(() => { 
  console.log('reslove')
}).then(() => {
  console.log('reslove1')
}).finally(() => { 
  console.log('finally')
}).catch(err => { 
  console.log(err)
})


const sleep2 = (times, data) => {
  return new MyPromise((reslove) => {
    setTimeout(() => reslove(data), times)
  })
}


MyPromise.all([sleep2(100, '111'), sleep2(200, '222')]).then(data => {
  console.log('all', data)
})

MyPromise.race([sleep2(100, '111'), sleep2(200, '222')]).then(data => { 
  console.log(data)
})

  